/*
 * Copyright (C) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "accessibility_flite_player.h"
#include "hilog_wrapper.h"

namespace OHOS {
namespace Accessibility {

FlitePlayer::FlitePlayer()
{
    Init();
}

FlitePlayer::~FlitePlayer()
{
    Release();
}

bool FlitePlayer::Init()
{
    HILOG_DEBUG();
    AudioStandard::AudioStreamType streamType = AudioStandard::AudioStreamType::STREAM_ACCESSIBILITY;
    renderer_ = AudioStandard::AudioRenderer::Create(streamType);
    if(renderer_ == nullptr){
        HILOG_ERROR("Init faied, audioRenderer is nullptr");
        return false;
    }
    supportedSampleList_=AudioStandard::AudioRenderer::GetSupportedSamplingRates();
    supportedChannelsList_=AudioStandard::AudioRenderer::GetSupportedChannels();
    if(supportedSampleList_.empty() || supportedChannelsList_.empty()){
        HILOG_DEBUG("supportedSampleList or supportedChannelsList is empty");
        renderer_->Release();
        renderer_ = nullptr;
        return false;
    }
    state_ = PlayerState::INIT_STATE;

    // 初始化buffer
    sampleBuffer_ = std::make_unique<uint8_t[]>(SAMPLE_BUFFER_CAPACITY);
    // 启动播放线程
    playThread_ = std::thread(&FlitePlayer::PlayBackThread, this);

    HILOG_DEBUG("Init success");
    return true;
}

bool FlitePlayer::Start()
{
    HILOG_DEBUG();
    if(!renderer_){
        HILOG_ERROR("Start failed, audioRenderer is nullptr");
        return false;
    }
    if(!renderer_->Start()){
        HILOG_DEBUG("Start failed");
        return false;
    }
    isRunning_ = true;
    state_ = PlayerState::STARTED_STATE;
    HILOG_DEBUG("Start success");
    return true;
}

bool FlitePlayer::Write(cst_wave *wave){
    HILOG_DEBUG();
    size_t bytesToWrite = cst_wave_num_samples(wave) * cst_wave_num_channels(wave) * sizeof(short); //cst_wave_io.c 244行
    size_t bytesWritten = 0;
    size_t minBytes = 4;
    //采用内存复制对样本数据进行类型转换
    std::vector<uint8_t> uint8Buffer(bytesToWrite); // 创建 uint8_t 数组   
    memcpy(uint8Buffer.data(), static_cast<uint8_t*>(static_cast<void*>(cst_wave_samples(wave))), bytesToWrite); // 使用 memcpy 转换内存块

    while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) {
        HILOG_DEBUG("start to write");
        bytesWritten += renderer_->Write(uint8Buffer.data() + bytesWritten, bytesToWrite - bytesWritten); // write第一个参数是uint8_t*类型
        if (bytesWritten < 0)
            break;
    }
    HILOG_DEBUG("bytesWritten: %{public}zu, bytesToWrite: %{public}zu", bytesWritten, bytesToWrite);
    return true;
}

bool FlitePlayer::WriteToBuffer(cst_wave *wave)
{
    HILOG_DEBUG();
    // 如果当前playthread正在执行，就将buffersize和isbuffered置为false，中断播放，等待playthread执行完毕
    if(isBuffered_){
        HILOG_DEBUG("buffer is not empty, wait for playthread to finish");
        isBuffered_ = false;
        bufferSize_ = 0;
    }
    {
        std::unique_lock<std::mutex> lock(mutex_);
        HILOG_DEBUG("start to write to buffer");
        // SetParams
        if(!SetParams(cst_wave_num_channels(wave), cst_wave_sample_rate(wave))){
            HILOG_ERROR("SetParams failed");
            return false;
        }
        // 填充buffer
        bufferSize_=cst_wave_num_samples(wave) * cst_wave_num_channels(wave) * sizeof(short);
        if(bufferSize_ > SAMPLE_BUFFER_CAPACITY){
            HILOG_ERROR("bufferSize_ > SAMPLE_BUFFER_CAPACITY");
            return false;
        }
        memcpy(sampleBuffer_.get(), static_cast<uint8_t*>(static_cast<void*>(cst_wave_samples(wave))), bufferSize_);
        isBuffered_ = true;
        HILOG_DEBUG("write to buffer success");
        cond_.notify_one();
    }
    return true;
}

// 未加锁，只在PlayBackThread中调用
bool FlitePlayer::WriteFromBuffer(){
    HILOG_DEBUG();
    size_t bytesToWrite = bufferSize_;
    size_t bytesWritten = 0;
    // 分多次写入样本数据，单词写入4096bytes，目的是让播放线程能够及时响应中断信号
    while(bytesWritten < bytesToWrite){
        if(bytesWritten + SINGLE_WRITE_BYTES <= bytesToWrite){
            bytesWritten += renderer_->Write(sampleBuffer_.get() + bytesWritten, SINGLE_WRITE_BYTES);
        }else{
            bytesWritten += renderer_->Write(sampleBuffer_.get() + bytesWritten, bytesToWrite - bytesWritten);
        }
        if (bytesWritten < 0 || bufferSize_==0 || !isBuffered_|| exitFlag_) break;
    }
    // while ((bytesWritten < bytesToWrite) && ((bytesToWrite - bytesWritten) > minBytes)) {
    //     HILOG_DEBUG("writing");
    //     // TODO: 可以考虑循环分批write，及时响应停止
    //     bytesWritten += renderer_->Write(sampleBuffer_.get() + bytesWritten, bytesToWrite - bytesWritten); // write第一个参数是uint8_t*类型
    //     if (bytesWritten < 0 || bufferSize_==0 || !isBuffered_|| exitFlag_) break;
    // }
    HILOG_DEBUG("write over, bytesWritten: %{public}zu, bytesToWrite: %{public}zu", bytesWritten, bytesToWrite);
    return true;
}

void FlitePlayer::PlayBackThread()
{
    while(!exitFlag_){
        std::unique_lock<std::mutex> lock(mutex_);
        if(!isBuffered_){
            cond_.wait(lock, [this](){return isBuffered_ || exitFlag_;}); // 等待buffer填充信号或退出信号
        }
        if(exitFlag_) break;
        HILOG_DEBUG("PlayBackThread start to play");
        if(!renderer_->Start()){
            HILOG_ERROR("PlayBackThread Start failed");
            continue;
        }
        WriteFromBuffer();
        // 无论是write完成还是中止，都清空缓冲区，开始下一次循环。
        bufferSize_=0;
        isBuffered_=false;
        if(!renderer_->Flush()||!renderer_->Stop()){
            HILOG_ERROR("PlayBackThread Flush or Stop failed");
        }
        HILOG_DEBUG("PlayBackThread end to play");
    }
    HILOG_DEBUG("PlayBackThread exit");
}

bool FlitePlayer::Pause()
{
    HILOG_DEBUG();
    if(!renderer_){
        HILOG_ERROR("Pause failed, audioRenderer is nullptr");
        return false;
    }
    if(!renderer_->Pause()){
        HILOG_DEBUG("Pause failed");
        return false;
    }
    state_ = PlayerState::PAUSED_STATE;
    HILOG_DEBUG("Pause success");
    return true;
}

bool FlitePlayer::Stop()
{
    HILOG_DEBUG();
    if(!renderer_){
        HILOG_ERROR("Stop failed, audioRenderer is nullptr");
        return false;
    }
    if(!renderer_->Stop()){
        HILOG_DEBUG("Stop failed");
        return false;
    }
    isRunning_ = false;
    state_ = PlayerState::STOPPED_STATE;
    HILOG_DEBUG("Stop success");
    return true;
}

bool FlitePlayer::Drain()
{
    HILOG_DEBUG();
    if(!renderer_){
        HILOG_ERROR("Drain failed, audioRenderer is nullptr");
        return false;
    }
    if(!renderer_->Drain()){
        HILOG_DEBUG("Drain failed");
        return false;
    }
    HILOG_DEBUG("Drain success");
    return true;
}

bool FlitePlayer::Flush()
{
    HILOG_DEBUG();
    if(!renderer_){
        HILOG_ERROR("Flush failed, audioRenderer is nullptr");
        return false;
    }
    if(!renderer_->Flush()){
        HILOG_DEBUG("Flush failed");
        return false;
    }
    HILOG_DEBUG("Flush success");
    return true;
}

bool FlitePlayer::Release()
{
    HILOG_DEBUG();
    //先释放播放线程资源
    exitFlag_ = true;
    cond_.notify_all();
    if(playThread_.joinable()){
        playThread_.join();
    }
    if(renderer_){
        renderer_->Release();
        renderer_ = nullptr;
    }
    return true;
}

bool FlitePlayer::SetParams(int32_t channels, int32_t sampleRate)
{
    HILOG_DEBUG("channels:%{public}d, sampleRate:%{public}d", channels, sampleRate);
    if(!renderer_){
        HILOG_ERROR("SetParams failed, audioRenderer is nullptr");
        return false;
    }
    AudioStandard::AudioRendererParams rendererParams;
    bool flag1=false, flag2=false; // 判断是否支持
    for(auto &c : supportedChannelsList_){
        if(c == channels){
            rendererParams.channelCount = c;
            flag1 = true;
            break;
        }
    }
    //尽可能刚好覆盖数据的采样率
    for(auto &s : supportedSampleList_){
        if(sampleRate<=s){
            rendererParams.sampleRate=s;
            flag2 = true;
            break;
        }
    }
    if(!flag1 || !flag2){
        HILOG_ERROR("SetParams failed, channels:%{public}d, sampleRate:%{public}d", channels, sampleRate);
        return false;
    }
    HILOG_DEBUG("find supported channels:%{public}d, sampleRate:%{public}d", rendererParams.channelCount, rendererParams.sampleRate);
    rendererParams.sampleFormat = AudioStandard::AudioSampleFormat::SAMPLE_S16LE;
    rendererParams.encodingType = AudioStandard::AudioEncodingType::ENCODING_PCM;
    if(renderer_->SetParams(rendererParams)!=0){
        HILOG_ERROR("SetParams failed");
        return false;
    }
    HILOG_DEBUG("SetParams success");
    return true;
}

bool FlitePlayer::Play(cst_wave *wave)
{
    HILOG_DEBUG();
    if (wave == nullptr) {
        HILOG_ERROR("wave is nullptr");
        return false;
    }
    WriteToBuffer(wave);
    // if(!renderer_){
    //     HILOG_DEBUG("audioRenderer is nullptr");
    //     Init();   
    // }
    // // 如果当前正在播放，就先清空缓冲区并stop
    // if(isRunning_){
    //     HILOG_DEBUG("isRunning_ is true");
    //     if(!Flush()||!Stop()){
    //         HILOG_ERROR("Flush or Stop failed");
    //     }
    // }
    // // SetParams
    // if(!SetParams(cst_wave_num_channels(wave), cst_wave_sample_rate(wave))){
    //     HILOG_ERROR("SetParams failed");
    //     return false;
    // }
    // if(!Start()){
    //     HILOG_ERROR("Start failed");
    //     return false;
    // }
    // Write(wave);
    // if(!Drain()||!Stop()){
    //     HILOG_ERROR("Drain or Stop failed");
    //     return false;
    // }
    HILOG_DEBUG("Play success");
    return true;
}

} // namespace Accessibility
} // namespace OHOS